// +FHDR------------------------------------------------------------
//                 Copyright (c) 2022 .
//                       ALL RIGHTS RESERVED
// -----------------------------------------------------------------
// Filename      : spt_driver.sv
// Author        : 
// Created On    : 2022-08-25 15:07
// Last Modified : 
// -----------------------------------------------------------------
// Description:
//
//
// -FHDR------------------------------------------------------------

`ifndef __SPT_DRIVER_SV__
`define __SPT_DRIVER_SV__

class spt_driver extends uvm_driver #(spt_transaction);

	virtual spt_interface vif;
    `ifdef UTILS_TEST
    uvm_analysis_port #(spt_transaction) ap;
    `endif
	`uvm_component_utils(spt_driver)

	extern function new(string name = "spt_driver", uvm_component parent=null);
	extern virtual function void build_phase(uvm_phase phase);
	extern virtual task main_phase(uvm_phase phase);
	extern virtual task drive_pkt(spt_transaction pkt);
	extern virtual task drive_idle();

endclass: spt_driver

function spt_driver::new(string name = "spt_driver", uvm_component parent=null);
	super.new(name, parent);
endfunction: new

function void spt_driver::build_phase(uvm_phase phase);
	super.build_phase(phase);
	`uvm_info("spt_driver", "build_phase is called", UVM_HIGH);
	if(!uvm_config_db #(virtual spt_interface)::get(this, "", "vif", vif))begin
		`uvm_fatal("spt_driver", "virtual interface get fatal");
	end
    `ifdef UTILS_TEST
    ap   = new("ap", this);
    `endif
endfunction: build_phase

task spt_driver::main_phase(uvm_phase phase);
	phase.raise_objection(this);
	`uvm_info("spt_driver", "main_phase is called", UVM_HIGH);
    
    this.drive_idle();
    while(!this.vif.rst_n) @this.vif.drv;

    @this.vif.drv;
	while(1)begin
        spt_transaction req;
		seq_item_port.try_next_item(req);
		if(req == null) break;
		else begin
            req.pack();
	        `uvm_info("spt_driver", "drive a pkt start", UVM_HIGH);
            `ifdef UTILS_TEST
            ap.write(req.clone());
            `endif
			this.drive_pkt(req);
			seq_item_port.item_done();
		end
	end
    this.drive_idle();

    #1000;
	phase.drop_objection(this);
endtask: main_phase

task spt_driver::drive_pkt(spt_transaction pkt);

    foreach(pkt.pkt_data[i])begin
        @this.vif.drv;
        this.vif.drv.valid <= 'd1;
        this.vif.drv.data  <= pkt.pkt_data[i];
    end
    repeat(pkt.cycle_post) this.drive_idle();
	
endtask: drive_pkt

task spt_driver::drive_idle();
    @this.vif.drv;
	this.vif.drv.valid <= 'd0;
    this.vif.drv.data  <= 'dx;
endtask: drive_idle

`endif
